﻿namespace WizardEngine.Core
{
    using System;
    using System.Collections.Generic;
    using Specification;
    using Persistence;

    internal class Wizard<T> : IWizard<T> where T : FlowState, new()
    {
        private readonly IDictionary<Step, IList<Transition<T>>> forwardTransitions = new Dictionary<Step, IList<Transition<T>>>();
        private readonly IDictionary<Step, IList<Transition<T>>> backwardTransitions = new Dictionary<Step, IList<Transition<T>>>();
        private readonly IFlowStatePersistenceProvider persistenceProvider;

        public Wizard(IFlowSpecification<T> specification, IFlowStatePersistenceProvider persistenceProvider)
        {
            this.persistenceProvider = persistenceProvider;
            this.ProcessSpecification(specification);
        }

        private void ProcessSpecification(IFlowSpecification<T> specification)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Advances the flow to the next step updating the flow state. 
        /// </summary>
        /// <remarks>
        /// If the current step was visited out of order it will reset flow instance identifier 
        /// to the state it had when visiting it previous time. 
        /// </remarks>
        /// <param name="flowInstanceId">Flow state instance identifier. </param>
        /// <param name="update">Piece of code updating the state</param>
        public void Advance(Guid flowInstanceId, FlowStateUpdate<T> update)
        {
            var state = this.persistenceProvider.Load<T>(flowInstanceId);
            var followingSteps = this.forwardTransitions[state.CurrentStep];
            foreach (var step in followingSteps)
            {
                if (step.Condition.Invoke(state))
                {
                    var updatedState = state.Clone() as T;
                    update.Invoke(updatedState);
                    state.Visit(step.Target, updatedState);
                    break;
                }
            }

            this.persistenceProvider.Save(state);
        }

        /// <summary>
        /// Goes one step back in the flow. 
        /// </summary>
        /// <param name="flowInstanceId">Flow state instance identifier. </param>
        public void Back(Guid flowInstanceId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Checks whether one may advance to the target step out of order. 
        /// </summary>
        /// <remarks>
        /// Only steps already visited can be navigated this way. 
        /// </remarks>
        /// <param name="flowInstanceId">Flow state instance identifier. </param>
        /// <param name="step">Target step to enter. </param>
        /// <returns>True if target step can be accessed, false otherwise. </returns>
        public bool TryEnter(Guid flowInstanceId, Step step)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Provides information about the current step for the flow instance. 
        /// </summary>
        /// <param name="flowInstanceId">Flow state instance identifier. </param>
        public Step GetCurrentStep(Guid flowInstanceId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Discards wizard flow
        /// </summary>
        /// <param name="flowInstanceId">Flow state instance identifier. </param>
        public void Discard(Guid flowInstanceId)
        {
            throw new NotImplementedException();
        }
    }
}
